#ifndef _L_APP_FRAMEWORK_111225_H
#define _L_APP_FRAMEWORK_111225_H

#include <lmacros.h>
#include <ltypes.h>
#include <lsimulator.h>
#include <lutility.h>

#include <string>

#include <boost/pool/detail/singleton.hpp>
#include <boost/smart_ptr.hpp>

#include <gl/openglut.h>

#ifdef L_APP_FRAMEWORK_WITHOUT_CONSOLE
#pragma comment( linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" )
#endif

#define AppFramework    llib::util::AppFramework_t::instance()

LLIB_BEGIN;
namespace util {

class _framework_prototype {
public:
    _framework_prototype();
    ~_framework_prototype();

    void    SetSimulator        (boost::shared_ptr<Simulator> sim) { BOOST_ASSERT(sim.use_count() != 0); pSimulator = sim; }
    void    SetSimulator        (Simulator* sim)                { BOOST_ASSERT(sim != NULL); pSimulator = boost::shared_ptr<Simulator>(sim); }
    void    SetWindowSize       (Uint16 width, Uint16 height)   { _windowWidth = width; _windowHeight = height; _statusChanged = TRUE; }
    void    SetWindowPosition   (Uint16 posX, Uint16 posY)      { _windowPosX = posX; _windowPosY = posY; _statusChanged = TRUE; }
    void    SetDisplayMode      (Uint32 mode)                   { _displayMode = mode; _statusChanged = TRUE; }
    void    SetFullScreen       (Boolean isFullScreen)          { _fullScreen = isFullScreen; _statusChanged = TRUE; }
    void    SetWindowTitle      (std::string title)             { _windowTitle = title; }

    // llib openGL application framework entry main
    // for using this, just call FrameworkMain in main function after every thing is done
    Int32   FrameworkMain(Int32 argc, Char** argv);
private:
    boost::shared_ptr<Simulator> pSimulator;

    Uint16              _windowWidth;
    Uint16              _windowHeight;
    Uint16              _windowPosX;
    Uint16              _windowPosY;
    Uint32              _displayMode;
    std::string         _windowTitle;
    Boolean             _fullScreen;
    Uint8               _mouseButton;

    Boolean             _statusChanged;

    Int32               _curTime;
    Int32               _lastTime;
    const Int32         _timeInterval;
    Int32               _frameCount;

    /* member functions */
    void            glInit                  (void);
    void            statusUpdate            (void);
    void            frameRender             (void);

    /* static functions (wrappers) */
    static void     displayFuncWrapper      (void);
    static void     idleFuncWrapper         (void);
    static void     keyboardFuncWrapper     (Uint8 key, Int32 x, Int32 y);
    static void     keyboardUpFuncWrapper   (Uint8 key, Int32 x, Int32 y);
    static void     mouseFuncWrapper        (Int32 button, Int32 state, Int32 x, Int32 y);
    static void     motionFuncWrapper       (Int32 x, Int32 y);
    static void     passiveMotionFuncWrapper(Int32 x, Int32 y);
    static void     specialFuncWrapper      (Int32 key, Int32 x, Int32 y);
    static void     specialUpFuncWrapper    (Int32 key, Int32 x, Int32 y);
    static void     reshapeFuncWrapper      (Int32 width, Int32 height);
    static void     closeFuncWrapper        (void);

};

typedef boost::details::pool::singleton_default<_framework_prototype> AppFramework_t;

}
LLIB_END;

#endif